package net.facelib.jni;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 同步锁对象<br>
 * 加锁模块通过 {@link #checkSyncLock()}方法阻塞,直到应用层通过{@link #unlock()}解锁后唤醒阻塞的线程
 * @author guyadong
 *
 */
public class SyncLock{
	static final SyncLock NULL_LOCK = new SyncLock();
	/**
	 * 默认最大等待次数
	 */
	public static int DEFAULT_MAX_WAIT_COUNT = 1;
	/**
	 * 默认最大等待间隔(毫秒)
	 */
	public static final long DEFAULT_WAIT_INTERNAL_MILLS = 200;
	/**
	 * 同步标志
	 */
	private volatile AtomicBoolean lockFlag = null;
	/**
	 * 最大等待次数
	 */
	private int maxWaitCount = DEFAULT_MAX_WAIT_COUNT;
	/**
	 * 最大等待间隔(毫秒)
	 */
	private long waitInternalMills = DEFAULT_WAIT_INTERNAL_MILLS;
	/**
	 * 构造方法<br>
	 * @param lockFlag 同步锁对象,为{@code false}时加锁
	 * @param timeoutMills 超时时间(毫秒),小于等于0使用默认值{@link SyncLock#DEFAULT_WAIT_INTERNAL_MILLS},等于0则无限等待
	 */
	SyncLock(AtomicBoolean lockFlag, long timeoutMills) {
		this.lockFlag = lockFlag;
		if(timeoutMills == 0){
			this.maxWaitCount = Integer.MAX_VALUE;
		} else if(timeoutMills < 0){
			this.maxWaitCount = DEFAULT_MAX_WAIT_COUNT;
		}else{
			this.maxWaitCount = (int)((timeoutMills + DEFAULT_WAIT_INTERNAL_MILLS - 1) / DEFAULT_WAIT_INTERNAL_MILLS);
		}		
	}
	/**
	 * 构造方法<br>
	 * 创建的实例为锁定状态
	 * @param timeoutMills 
	 * @see #SyncLock(AtomicBoolean, long)
	 */
	SyncLock(long timeoutMills) {
		this(new AtomicBoolean(false),timeoutMills);
	}
	/**
	 * 默认构造方法<br>
	 * 创建的实例为无锁状态
	 */
	SyncLock() {
	}
	/**
	 * 当外部同步信号为false时阻塞,直到被唤醒。
	 * 如果指定的超时时间(waitInternalMills*maxWaitCount),则超时后抛出{@link SyncLockTimeoutException}异常
	 */
	void checkSyncLock(){
		int waitCount = maxWaitCount;
		// 为防止lockFlag可能会在阻塞期间被置为null,这里赋值到临时变量
		AtomicBoolean local ;
		while(null != (local = lockFlag) && !local.get()){
			if(waitCount-- <= 0){
				throw new SyncLockTimeoutException("sync lock waiting  timeout");
			}
			synchronized (local) {					
				try {
					local.wait(waitInternalMills);
				} catch (InterruptedException e) {
					throw new IllegalStateException("sync lock waiting interrupted");
				}
			}
		}
	}
	/**
	 * 删除同步锁
	 */
	public void clear(){
		unlock();
		lockFlag = null;
	}
	/**
	 * 同步锁复位,阻塞算法初始化线程
	 */
	public void lock(){
		// 为防止lockFlag可能会在阻塞期间被置为null,这里赋值到临时变量
		AtomicBoolean local = lockFlag;
		if(null != local ){
			synchronized (local) {
				local.set(false);
			}	
		}
	}
	/**
	 * 打开同步锁,唤醒所有阻塞的线程
	 */
	public void unlock(){
		// 为防止lockFlag可能会在阻塞期间被置为null,这里赋值到临时变量
		AtomicBoolean local = lockFlag;
		if(null != local ){
			synchronized (local) {
				lockFlag.set(true);
				lockFlag.notifyAll();
			}
		}				
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("SyncLock [lockFlag=");
		builder.append(lockFlag);
		builder.append(", maxWaitCount=");
		builder.append(maxWaitCount);
		builder.append(", waitInternalMills=");
		builder.append(waitInternalMills);
		builder.append("]");
		return builder.toString();
	}

	/**
	 * 同步锁超时异常
	 * @author guyadong
	 *
	 */
	public static class SyncLockTimeoutException extends RuntimeException{
		private static final long serialVersionUID = 1L;

		public SyncLockTimeoutException(String message) {
			super(message);
		}
		
	}
}